/* -*-c++-*-
 * This source code is proprietary of ADIT
 * Copyright (C) 2016 Advanced Driver Information Technology Joint Venture GmbH
 * All rights reserved
 *
 * Author: Rudolf Dederer <rudolf.dederer@de.bosch.com>
*/

#ifndef OSGBATCHEDTEXT_BATCHELEMENTBASE
#define OSGBATCHEDTEXT_BATCHELEMENTBASE 1

#include <osgBatchedText/BatchDrawableBase>
#include <osgBatchedText/Export>

namespace osgBatchedText {

class OSGBATCHEDTEXT_EXPORT BatchElementRenderInfo
{
public:
   enum OnScreen
   {
      CENTER_OUTSIDE,
      CENTER_INSIDE,
      COMPLETE_INSIDE
   };

   BatchElementRenderInfo(BatchDrawableBase::tShaderType shaderType = BatchDrawableBase::STRAIGHT_SCREEN, float alpha = 0.0f,
                          const FloatAndHalfFloat& vertexCompW = FloatAndHalfFloat(0), bool enableDepthTest = true, 
                          const osg::Vec3& transVec = osg::Vec3(), bool transVecValid = false, unsigned char displayOrder = 0,
                          float cosPitchAngleFactor = 1.0f, int displayPriority = 0, 
                          unsigned int refNr = 0, const osg::BoundingSphere& bsScreen = osg::BoundingSphere(),
                          BatchElementRenderInfo::OnScreen onScreen = BatchElementRenderInfo::COMPLETE_INSIDE,
                          bool isPickable = true, bool highlight = false)
      : _shaderType(shaderType), _alpha(alpha), _vertexCompW(vertexCompW), _transVec(transVec), _transVecValid(transVecValid),
        _displayOrder(displayOrder), _enableDepthTest(enableDepthTest), _isPickable(isPickable),
        _highlight(highlight), _cosPitchAngleFactor(cosPitchAngleFactor), _refNr(refNr), _bsScreen(bsScreen), _onScreen(onScreen), _nextElementIndex(0), _displayPriority(displayPriority) {}

   BatchDrawableBase::tShaderType _shaderType;

   /** operator to sort similar objects by their priority */
   bool operator < (const BatchElementRenderInfo& rhs) const;

   /** alpha value of object */
   float _alpha;
   /** cosine of pitch angle for sliding center of straight text */
   float _cosPitchAngleFactor;

   /** w component of vertex, can be overloaded */
   FloatAndHalfFloat _vertexCompW;

   /** reference number to search similar elements in screen space */
   unsigned int _refNr;

   /** bounding sphere in screen coordinates */
   osg::BoundingSphere _bsScreen;

   /** true if position of label is on screen */
   OnScreen _onScreen;

   /** display order of element: the ones with lower order are drawn first when sorting by display order is switched on */
   unsigned char _displayOrder;

   /** depth test can be switched on and off by this variable */
   bool _enableDepthTest;

   /** true if element can be picked, requires a picking implementation */
   bool _isPickable;

   /** true if item should be highlighted: then a special highlight configuration, e.g. for color, can be used */
   bool _highlight;

   /** true if transVec is already calculated */
   bool _transVecValid;

   /** transposition vector of the element */
   osg::Vec3 _transVec;

   mutable unsigned int _nextElementIndex;

   int _displayPriority;
};


class OSGBATCHEDTEXT_EXPORT BatchElementBase : public osg::Referenced
{
public:
   /** constructors */
   BatchElementBase(uintptr_t objectPointer) : _objectPointer(objectPointer) {}

   /** destructor */
   virtual ~BatchElementBase() {}

   uintptr_t getObjectPointer() const { return _objectPointer; }

   virtual unsigned int getNumberOfVertices() const { return 0; }

   virtual bool calcTransVector(const osg::Matrix& mvMat, osg::Vec3& transVec) const { return false; }

   virtual bool setVertexAttributes(BatchedVertexAttributes& vertexAttributes, const BatchElementRenderInfo& batchElementRenderInfo,
                                    BatchDrawParams& batchDrawParams, const osg::Vec4& color, bool overrideColor) const { return true; }

protected:
   uintptr_t _objectPointer;
};

class TextSimpleBase;

class OSGBATCHEDTEXT_EXPORT BatchElementTextBase : public BatchElementBase
{
public:
   /** constructors */
   BatchElementTextBase(const TextSimpleBase* textSimpleBase = NULL, const osg::Vec4& color = osg::Vec4(), const osg::Vec4& backdropColor = osg::Vec4(),
                        unsigned int numChars = 0, unsigned int beginOffset = 0)
      : BatchElementBase(reinterpret_cast<uintptr_t>(textSimpleBase)), _textSimpleBase(textSimpleBase), _color(color), _backdropColor(backdropColor), _numChars(numChars), _beginOffset(beginOffset) {}

   void set(const TextSimpleBase* textSimpleBase = NULL, const osg::Vec4& color = osg::Vec4(), const osg::Vec4& backdropColor = osg::Vec4(),
            unsigned int numChars = 0, unsigned int beginOffset = 0);
   /** destructor */
   virtual ~BatchElementTextBase() {}

   virtual unsigned int getNumberOfVertices() const;

   virtual bool calcTransVector(const osg::Matrix& mvMat, osg::Vec3& transVec) const;

   virtual bool setVertexAttributes(BatchedVertexAttributes& vertexAttributes, const BatchElementRenderInfo& batchElementRenderInfo,
                                    BatchDrawParams& batchDrawParams, const osg::Vec4& color, bool overrideColor) const;

   bool checkGlyphsInTexture(BatchedVertexAttributes& vertexAttributes, BatchDrawParams& batchDrawParams) const;

protected:
   const TextSimpleBase* _textSimpleBase;
   unsigned int _numChars;
   unsigned int _beginOffset;

   /** color of text */
   osg::Vec4 _color;
   /** color of outline */
   osg::Vec4 _backdropColor;
};

class OSGBATCHEDTEXT_EXPORT BatchElementContainer : public osg::Referenced
{
public:
   BatchElementContainer(const BatchElementRenderInfo& renderInfo = BatchElementRenderInfo()) : _renderInfo(renderInfo) {}

   /** destructor */
   virtual ~BatchElementContainer() {}

   virtual bool isPickable() { return false; }

   bool operator==(const BatchElementContainer& rhs) const;
   bool operator<(const BatchElementContainer& rhs) const;

   bool setVertexAttributes(BatchedVertexAttributes& vertexAttributes, BatchDrawParams& batchDrawParams) const;

   unsigned int getNumberOfVertices() const;

   void calcTransVector(const osg::Matrix& mvMat);

   static bool z_comparator(const osg::ref_ptr<BatchElementContainer>& container1, const osg::ref_ptr<BatchElementContainer>& container2);
   static bool sortBasedOnDisplayOrder(const osg::ref_ptr<BatchElementContainer>& container1, const osg::ref_ptr<BatchElementContainer>& container2);

   class clIsSame
   {
   public:
      clIsSame(const osg::ref_ptr<BatchElementContainer>& rhs) : _container(rhs.get()){}
      bool operator() (const osg::ref_ptr<BatchElementContainer>& lhs) const { return (*lhs == *_container); }
   private:
      const BatchElementContainer* _container;
   };

   std::vector< osg::ref_ptr<BatchElementBase> > _batchElements;
   BatchElementRenderInfo _renderInfo;
};


inline bool BatchElementContainer::z_comparator(const osg::ref_ptr<BatchElementContainer>& container1, const osg::ref_ptr<BatchElementContainer>& container2)
{
   return (container1->_renderInfo._transVec.z() < container2->_renderInfo._transVec.z());
}

}

#endif //OSGBATCHEDTEXT_BATCHELEMENTBASE
